#ifndef _MAP_H_
#define _MAP_H_

#include "common.h"
#include "array.h"

#include "content.h"
#include "thread.h"

#define CHUNKSIZE			16

#define CHUNK_TIMESTAMP_UNDEFINED	0xFFFFFFFF

#define CHUNK_STATE_CLEAN		0x00 /* unmodified */
#define CHUNK_STATE_WRITE_AT_UNLOAD	0x01 /* modified, save when unloaded */
#define CHUNK_STATE_WRITE_NEEDED	0x02 /* modified, save ASAP */
#define CHUNK_STATE_UNDERGROUND		0x04 /* old is_underground = true */
#define CHUNK_STATE_BADLIGHT		0x08 /* old light_expired = true */
#define CHUNK_STATE_BADMESH		0x10 /* old mesh_expired = true */
#define CHUNK_STATE_UNGENERATED		0x20
#define CHUNK_STATE_BADSPAWN		0x40
#define CHUNK_STATE_EMPTY		0x80 /* contains only air/vacuum - a speed up for meshgen */

#define MAPOCT_MINUS_XYZ	0
#define MAPOCT_MINUS_XY_PLUS_Z	1
#define MAPOCT_MINUS_X_PLUS_YZ	2
#define MAPOCT_MINUS_XZ_PLUS_Y	3
#define MAPOCT_MINUS_YZ_PLUS_X	4
#define MAPOCT_MINUS_Z_PLUS_XY	5
#define MAPOCT_MINUS_Y_PLUS_XZ	6
#define MAPOCT_PLUS_XYZ		7

#define MAP_NORTH		0x00
#define MAP_SOUTH		0x01
#define MAP_EAST		0x02
#define MAP_WEST		0x04
#define MAP_UP			0x08
#define MAP_DOWN		0x10

#define MAP_X_MINUS		MAP_WEST
#define MAP_X_PLUS		MAP_EAST
#define MAP_Y_MINUS		MAP_DOWN
#define MAP_Y_PLUS		MAP_UP
#define MAP_Z_MINUS		MAP_NORTH
#define MAP_Z_PLUS		MAP_SOUTH

#define MAP_NORTH_INDEX		0
#define MAP_SOUTH_INDEX		1
#define MAP_EAST_INDEX		2
#define MAP_WEST_INDEX		3
#define MAP_UP_INDEX		4
#define MAP_DOWN_INDEX		5

#define MAP_X_MINUS_INDEX	MAP_WEST_INDEX
#define MAP_X_PLUS_INDEX	MAP_EAST_INDEX
#define MAP_Y_MINUS_INDEX	MAP_DOWN_INDEX
#define MAP_Y_PLUS_INDEX	MAP_UP_INDEX
#define MAP_Z_MINUS_INDEX	MAP_NORTH_INDEX
#define MAP_Z_PLUS_INDEX	MAP_SOUTH_INDEX

#define MAP_TRIGGER_MIN		0x00
#define MAP_TRIGGER_MAX		0x02
#define MAP_TRIGGER_COUNT	3

#define MAP_TRIGGER_LOADED	0x00
#define MAP_TRIGGER_UNLOAD	0x01
#define MAP_TRIGGER_UPDATE	0x02

#ifndef _HAVE_BLOCK_TYPE
#define _HAVE_BLOCK_TYPE
typedef struct block_s {
	content_t content;
	uint8_t param1;
	uint8_t param2;
	uint16_t param3;
	uint32_t envticks;
} block_t;
#endif

#ifndef _HAVE_CHUNK_TYPE
#define _HAVE_CHUNK_TYPE
struct mapoct_s;
typedef struct chunk_s {
	struct chunk_s *prev;
	struct chunk_s *next;
	struct mapoct_s *mapoct;
	int mapoct_index;
	pos_t pos;
	block_t blocks[CHUNKSIZE][CHUNKSIZE][CHUNKSIZE];
	uint32_t timestamp;
	float idletime;
	uint8_t state;

	struct {
		array_t data;
		pos_t spawn;
		uint32_t last;
	} mobs;

	struct {
		void *obj;
		mutex_t *mut;
		array_t sounds;
	} mesh;

	array_t metadata;
} chunk_t;
#endif

#ifndef _HAVE_MAPOCT_TYPE
#define _HAVE_MAPOCT_TYPE
typedef struct mapoct_s {
	uint32_t size;
	pos_t pos;
	struct mapoct_s *parent;
	int parent_index;
	struct mapoct_s *children[8];
	chunk_t *chunks[8];
} mapoct_t;
#endif

/* defined in map.c */
int map_init(void);
void map_clear(void);
void map_exit(void);
void map_add_chunk(chunk_t *ch);
void map_delete_chunk(chunk_t *ch);
chunk_t *map_get_chunk_containing(pos_t *p);
block_t *map_get_block(pos_t *p);
void map_set_block(pos_t *p, block_t *b);

/* defined in map_trigger.c */
int map_trigger(uint32_t type, chunk_t *ch, pos_t *p);
int map_trigger_add(uint32_t type, void (*fn)(chunk_t*,pos_t*));
void map_trigger_clear(void);

/* defined in mapgen.c */
int mapgen_queue_max_setter(char* v);
int mapgen_init(void);
void mapgen_exit(void);
void mapgen_request(pos_t *p);

/* defined in mapgen_noise.c */
void mapgen_seed(int s);
float noise_height(int x, int z);

#ifdef _MAPGEN_LOCAL
/* defined in mapgen_basic.c */
void mapgen_underground(pos_t *p);
void mapgen_space(pos_t *p);
void mapgen_air(pos_t *p);

/* defined in mapgen_terrain.c */
void mapgen_terrain(pos_t *p);

/* defined in mapgen_util.c */
void mapgen_fill_chunk(chunk_t *ch, content_t id);
chunk_t *mapgen_create_chunk(pos_t *p);

#endif

#endif
